package com.brillilab.service.logic.user;

import com.alibaba.fastjson.JSONObject;
import com.brillilab.common.constant.*;
import com.brillilab.common.entity.ResponseVo;
import com.brillilab.common.exceptions.BrillilabException;
import com.brillilab.common.redis.RedisCache;
import com.brillilab.common.utils.*;
import com.brillilab.config.InviteCodeProperties;
import com.brillilab.config.UserLoginProperties;
import com.brillilab.domain.enums.common.BoolEnum;
import com.brillilab.domain.enums.lab.*;
import com.brillilab.domain.po.lab.*;
import com.brillilab.domain.po.system.SystemConfig;
import com.brillilab.domain.po.team.TeamMember;
import com.brillilab.domain.po.user.InviteCode;
import com.brillilab.domain.po.user.UserInviteAudit;
import com.brillilab.domain.po.user.Users;
import com.brillilab.domain.vo.home.HomeInviteCodeInfo;
import com.brillilab.domain.vo.home.HomeInviteCodeItemVo;
import com.brillilab.domain.vo.lab.LabInfoVo;
import com.brillilab.domain.vo.lab.PowerAndDutyModifyVo;
import com.brillilab.domain.vo.user.*;
import com.brillilab.service.core.email.impl.EmailServiceImpl;
import com.brillilab.service.core.lab.*;
import com.brillilab.service.core.system.IDictService;
import com.brillilab.service.core.system.ISystemConfigService;
import com.brillilab.service.core.team.ITeamMemberService;
import com.brillilab.service.core.user.IInviteCodeService;
import com.brillilab.service.core.user.IUserInviteAuditService;
import com.brillilab.service.core.user.IUsersService;
import com.brillilab.service.logic.lab.LabApplyLogic;
import com.brillilab.service.logic.lab.LabMemberLogic;
import com.brillilab.service.logic.message.MessageLogic;
import com.brillilab.service.module.aliyun.AliYunSms;
import com.brillilab.service.module.message.producer.MessageProducer;
import com.brillilab.service.module.message.template.impl.usercenter.RegisterSuccessTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户服务提供者
 *
 * @author wmh
 */
@Service
@Transactional
@Slf4j
public class UsersLogic {

    @Resource
    private IUsersService usersService;
    @Resource
    private ILabUserCardService cardService;
    @Resource
    private ILabMemberService labMemberService;
    @Resource
    private LabMemberLogic labMemberLogic;
    @Resource
    private ILabMemberPowerService labMemberPowerService;
    @Resource
    private ILabUserCardService labUserCardService;
    @Resource
    private ITeamMemberService teamMemberService;

    @Resource
    private MessageLogic messageLogic;
    @Resource
    private ILabService labService;
    @Resource
    private RedisCache redisCache;
    @Resource
    private MessageProducer messageProducer;
    @Resource
    private ILabApplyService labApplyService;
    @Resource
    private IUserInviteAuditService userInviteAuditService;
    @Resource
    private UserInviteAuditLogic userInviteAuditLogic;
    @Resource
    private EmailServiceImpl emailService;
    @Resource
    private IDictService dictService;
    @Resource
    private AliYunSms aliYunSms;
    @Resource
    private ILabJoinAuditService labJoinAuditService;
    @Resource
    private LabApplyLogic labApplyLogic;
    @Resource
    private IInviteCodeService inviteCodeService;
    @Resource
    private InviteCodeProperties properties;
    @Resource
    private ISystemConfigService systemConfigService;

    @Autowired
    private UserLoginProperties userLoginProperties;

    /**
     * 新用户注册
     *
     * @param labId
     * @param mobile
     * @param password
     * @param userName
     * @param duty
     * @param entryDate
     * @return
     */
    public Users userRegister(Long labId, String mobile, String password, String userName, String duty, Date entryDate,
                              String certificateNo) {
        // 用户校验
        Users exist = usersService.selectUser(mobile, UserEnum.State.NORMAL.getValue());
        Assert.isTrue(exist == null, "手机号码已被注册！");
        // 实验室校验
        Lab lab = labService.selectById(labId);
        Assert.notNull(lab, "实验室不存在！");

        // 创建用户
        Users user = createUsersAndInsert(labId, mobile, password, userName, certificateNo);

        // 插入实验室成员
        LabMember labMember = labMemberLogic.createLabMemberAndInsert(labId, user.getId(), duty, entryDate);
        Assert.isTrue(labMember != null && labMember.getId() != null, "成员创建失败！");

        // 接收推荐方法
        labMemberLogic.recommendMethodInit(lab, labMember);

        // 推送提醒
        Long receiverId = lab.getOwnerId();// 接收人：实验室PI
        Long receiverLabMemberId = labMember.getId();

        // 过滤PI本人注册时的推送
        if (!user.getId().equals(receiverId)) {
            RegisterSuccessTemplate registerSuccessTemplate = new RegisterSuccessTemplate(labId, receiverId,
                    receiverLabMemberId, lab.getName(), userName, user.getId());
            messageProducer.sendMessagePush(registerSuccessTemplate);
        }

        return user;

    }

    /**
     * 内部密码和数据密码已默认MD5加密，直接传入明文
     *
     * @param labId
     * @param mobile
     * @param password
     * @param userName
     * @param certificateNo
     * @return
     */
    public Users createUsersAndInsert(Long labId, String mobile, String password, String userName,
                                      String certificateNo) {
        Users user = new Users();
        user.setLabId(labId);
        user.setMobile(mobile);
        user.setName(userName);
        user.setImageUrl("https://labinone-public.oss-cn-hangzhou.aliyuncs.com/image/default/user_default.png");
        certificateNo = StringUtils
                .lowerCase(StringUtils.isNotBlank(certificateNo) ? certificateNo.trim() : certificateNo);
        user.setCertificateNo(certificateNo);
        user.setPassword(DigestUtils.md5Hex(password.trim()).toUpperCase());
        user.setSecurityPwd(StringUtils.isNotBlank(certificateNo)
                ? DigestUtils.md5Hex(StringUtils.substring(certificateNo, certificateNo.length() - 6)).toUpperCase()
                : null);

        // 默认过期时间为30天
        Date expireDate = DateUtil.addDate(new Date(), 30);
        String dateString = DateUtil.dateString(expireDate, "yyyy-MM-dd 23:59:59");
        user.setExpireDate(DateUtil.stringToDate(dateString, "yyyy-MM-dd HH:mm:ss"));

//        // 注册网易云信
//        IMAccountVo imUser = messageLogic.createIMUser(CodeUtil.getUUID(), user.getName());
//
//        if (imUser != null) {
//            user.setImAccount(imUser.getAccid());
//            user.setImToken(imUser.getToken());
//        }

        // 插入用户
        return usersService.insert(user);
    }

    /**
     * 用户磁卡注册
     *
     * @param labId
     * @param cardNo
     * @param mobile
     * @param password
     * @param userName
     * @param duty
     * @param entryDate
     * @return
     */
    public Users userRegisterWithCard(Long labId, String cardNo, String mobile, String password, String userName,
                                      String duty, Date entryDate, String certificateNo) {

        // 用户注册
        Users user = userRegister(labId, mobile, password, userName, duty, entryDate, certificateNo);
        // 绑卡
        labUserCardService.bindCard(labId, cardNo, user.getId());

        return user;
    }

    /**
     * 用户账号登录
     * <p>
     * 参数 mobile password labId 一体机： 必传labId web,app：
     *
     * @return
     */
    public UserInfoVo userLogin(Long labId, String mobile, String password, ClientTypeEnum clientType) {
        // 审核情况
        labApplyAndLabJoinApplyDeal(labId, mobile, clientType);
        // 存在用户校验密码
        Users users = usersService.selectUser(mobile, password, null);
        Assert.isTrue(users != null, clientType.equals(ClientTypeEnum.AIO) ? "密码错误!" : "手机号或密码错误!");
        // 成员
        labId = labId != null ? labId : users.getLabId();
        List<LabMember> labMemberList = labMemberService.selectListByUserId(users.getId());
        if (labId == null && !CollectionUtils.isEmpty(labMemberList)) {
            labId = labMemberList.get(0).getLabId();
            users.setLabId(labId);
        }
        // 生成设置用户缓存信息
        UserInfoVo userInfo = generateLoginUserCacheInfo(labId, clientType, users, labMemberList);
        // 更新登录时间
        updateUserLoginInfo(users);

        return userInfo;
    }

    /* 更新用户登录信息 */
    private void updateUserLoginInfo(Users users) {
        Date now = new Date();
        if (users.getFirstLoginTime() == null && users.getIsChangedPwd() == 1) {
            users.setFirstLoginTime(now); // 首次登录时间
        }
        users.setLastLoginTime(now); // 最近登录时间
        usersService.updateById(users);
    }

    /* 生成设置用户缓存信息 */
    private UserInfoVo generateLoginUserCacheInfo(Long labId, ClientTypeEnum clientType, Users users,
                                                  List<LabMember> labMemberList) {
        UserInfoVo userInfo = MyBeanUtils.copyBean(users, UserInfoVo.class);
        if (labId != null) {
            // 获取实验室相关信息
            Lab lab = labService.selectById(labId);
            Assert.notNull(lab, "实验室不存在");
            // 到期判断
//            if(lab.getExpireDate().getTime() < System.currentTimeMillis()){
//                throw new BrillilabException(ResultEnum.LAB_EXPIRE,"您所在的实验室已到期,请联系您的PI进行处理!");
//            }

            // 成员
            LabMember labMember = labMemberService.selectMember(labId, users.getId());
            if (labMember == null) {
                List<UserInviteAudit> userInviteAuditList = userInviteAuditService.selectListByMobile(users.getMobile(),
                        false);
                UserInviteAudit userInviteAudit = userInviteAuditList.stream().findFirst().orElse(null);
                doUserInviteAuditDeal(clientType, userInviteAudit);
            }
            Assert.isTrue(labMember != null, "成员已被移出实验室！");

            if (lab.getOwnerId() == null
                    && !labMemberPowerService.isPower(labId, labMember.getId(), LabMemberPowerEnum.Power.USER_MANAGE)) {
                throw new BrillilabException(ResultEnum.LAB_NO_PI_OR_LAB_AUDIT_WAIT_PC, "只有在PI注册完成以后才可以登录，请您耐心等待！");
            }
            // teamMember
            TeamMember teamMember = teamMemberService.selectByLabMemberId(labMember.getId());
            // power
            List<LabMemberPower> powers = labMemberPowerService.selectList(labId, labMember.getId());

            if (teamMember != null && teamMember.getIsLeader().equals(BoolEnum.TRUE.getValue())) {
                userInfo.setIsTeamLeader(BoolEnum.TRUE.getValue());
            } else {
                userInfo.setIsTeamLeader(BoolEnum.FALSE.getValue());
            }
            Users user = usersService.selectUser(lab.getOwnerId(), null);
            if (user != null) {
                userInfo.setPiFirstLoginTime(user.getFirstLoginTime());
            }
            userInfo.setLabId(labId);
            userInfo.setLabName(lab.getName());
            userInfo.setOwnerId(lab.getOwnerId());
            userInfo.setLabMemberId(labMember.getId());
            userInfo.setIsVip(lab.getIsVip());
            userInfo.setLabNum(labMemberList != null ? labMemberList.size() : 0);
            userInfo.setDuty(labMember.getDuty());
            userInfo.setPowers(powers);
            userInfo.setUserPayType(users.getPayType());

            // setLabExpireInfo(userInfo, lab);
//            setUserExpireInfo(userInfo);

        } else {
            userInfo.setIsTeamLeader(BoolEnum.FALSE.getValue());
            userInfo.setIsVip(BoolEnum.FALSE.getValue());
            userInfo.setLabNum(BoolEnum.FALSE.getValue());
            userInfo.setExpireDays(0);
            userInfo.setHasExpired(false);
        }

        // 设置用户登录信息缓存
        this.setUserCache(userInfo, clientType);

        return userInfo;
    }

    /* 登录审核情况提示语 */
    private void labApplyAndLabJoinApplyDeal(Long labId, String mobile, ClientTypeEnum clientType) {
        Users users = usersService.selectUser(mobile, UserEnum.State.NORMAL.getValue());
        // 成员审核
        if (users != null) {
            labId = labId != null ? labId : users.getLabId();
            if (labId == null) {
                // 审阅
                List<LabJoinAudit> audits = labJoinAuditService.selectList(users.getId(), LabJoinAuditStateEnum.WAIT);
                if (CollectionUtils.isEmpty(audits)) {
                    throw new BrillilabException(ResultEnum.NO_LAB, "您尚未加入实验室请先联系您的实验室PI进行成员邀请!");
                } else {
                    throw new BrillilabException(ResultEnum.NO_LAB, "您的申请已提交,请您耐心等待PI审核!");
                }
            }
        }

        // 实验室审核
        List<LabApply> labApplies = labApplyService.selectListByMobile(mobile, false);
        LabApply labApply = labApplies.stream().findFirst().orElse(null);

        // 实验室成员审核
        List<UserInviteAudit> userInviteAuditList = userInviteAuditService.selectListByMobile(mobile, false);
        UserInviteAudit userInviteAudit = userInviteAuditList.stream().findFirst().orElse(null);

        // 具体处理
        if (labApply != null) {
            doLabApplyDeal(clientType, labApply);
        } else if (labApply == null && userInviteAudit != null && users == null) {
            doUserInviteAuditDeal(clientType, userInviteAudit);
        } else if (labApply != null && userInviteAudit != null
                && labApply.getUpdateTime().getTime() >= userInviteAudit.getUpdateTime().getTime()) {
            doLabApplyDeal(clientType, labApply);
        } else if (labApply != null && userInviteAudit != null
                && labApply.getUpdateTime().getTime() < userInviteAudit.getUpdateTime().getTime() && users == null) {
            doUserInviteAuditDeal(clientType, userInviteAudit);
        }

        // 手机号是否注册
        Assert.notNull(users, "该手机号未注册!");
    }

    private void doUserInviteAuditDeal(ClientTypeEnum clientType, UserInviteAudit userInviteAudit) {
        if (userInviteAudit != null) {
            String auditInfo = userInviteAudit.getAuditInfo();
            if (userInviteAudit.getState().equals(UserInviteAuditStateEnum.WAIT_AUDIT.getValue())
                    && clientType.equals(ClientTypeEnum.PC)) {
                throw new BrillilabException(ResultEnum.LAB_NO_PI_OR_LAB_AUDIT_WAIT_PC,
                        "您的申请已经提交，我们会在1-3个工作日内审核完成，审核完成后短信通知您，请您耐心等待！");
            } else if ((userInviteAudit.getState().equals(UserInviteAuditStateEnum.WAIT_AUDIT.getValue())
                    && !clientType.equals(ClientTypeEnum.PC))) {
                throw new BrillilabException(ResultEnum.LAB_AUDIT_WAIT_APP,
                        "您的申请已经提交，我们会在1-3个工作日内审核完成，审核完成后短信通知您，请您耐心等待！");
            } else if ((userInviteAudit.getState().equals(UserInviteAuditStateEnum.WAIT_CHECK.getValue())
                    && clientType.equals(ClientTypeEnum.PC))) {
                throw new BrillilabException(ResultEnum.LAB_NO_PI_OR_LAB_AUDIT_WAIT_PC,
                        "您已经提交申请实验室信息，请您在邮箱中点击链接验证后再进行登录！");
            } else if ((userInviteAudit.getState().equals(UserInviteAuditStateEnum.WAIT_CHECK.getValue())
                    && !clientType.equals(ClientTypeEnum.PC))) {
                throw new BrillilabException(ResultEnum.LAB_AUDIT_WAIT_APP, "您已经提交申请实验室信息，请您在邮箱中点击链接验证后再进行登录！");
            } else if ((userInviteAudit.getState().equals(UserInviteAuditStateEnum.WAIT_PI_AUDIT.getValue())
                    && clientType.equals(ClientTypeEnum.PC))) {
                throw new BrillilabException(ResultEnum.LAB_NO_PI_OR_LAB_AUDIT_WAIT_PC, "您的申请已经提交，需要PI审核成功后才可以加入实验室！");
            } else if ((userInviteAudit.getState().equals(UserInviteAuditStateEnum.WAIT_PI_AUDIT.getValue())
                    && !clientType.equals(ClientTypeEnum.PC))) {
                throw new BrillilabException(ResultEnum.LAB_AUDIT_WAIT_APP, "您的申请已经提交，需要PI审核成功后才可以加入实验室！");
            } else if (userInviteAudit.getState().equals(UserInviteAuditStateEnum.AUDIT_NOT_PASS.getValue())
                    && !clientType.equals(ClientTypeEnum.PC)) {
                if (StringUtils.isNotBlank(auditInfo)) {
                    auditInfo = String.format("您的实验室成员申请未通过，原因如下：%s", userInviteAudit.getAuditInfo());
                } else {
                    auditInfo = "您的实验室成员申请未通过";
                }
                throw new BrillilabException(ResultEnum.USER_INVITE_AUDIT_NOT_PASS, auditInfo);

            } else if (userInviteAudit.getState().equals(UserInviteAuditStateEnum.AUDIT_NOT_PASS.getValue())
                    && clientType.equals(ClientTypeEnum.PC)) {
                if (StringUtils.isNotBlank(auditInfo)) {
                    auditInfo = String.format("您的实验室成员申请未通过，原因如下：%s", userInviteAudit.getAuditInfo());
                } else {
                    auditInfo = "您的实验室成员申请未通过";
                }
                throw new BrillilabException(ResultEnum.LAB_AUDIT_FAIL, auditInfo);
            }
        }
    }

    private void doLabApplyDeal(ClientTypeEnum clientType, LabApply labApply) {
        if (labApply != null) {
            String auditInfo = labApply.getAuditInfo();
            if (labApply.getState().equals(LabAuditStateEnum.WAIT_AUDIT.getValue())
                    && clientType.equals(ClientTypeEnum.PC)) {
                throw new BrillilabException(ResultEnum.LAB_NO_PI_OR_LAB_AUDIT_WAIT_PC,
                        "您的申请已经提交，我们会在1-3个工作日内审核完成，审核完成后短信通知您，请您耐心等待！");
            } else if ((labApply.getState().equals(LabAuditStateEnum.WAIT_AUDIT.getValue())
                    && !clientType.equals(ClientTypeEnum.PC))) {
                throw new BrillilabException(ResultEnum.LAB_AUDIT_WAIT_APP,
                        "您的申请已经提交，我们会在1-3个工作日内审核完成，审核完成后短信通知您，请您耐心等待！");
            } else if ((labApply.getState().equals(LabAuditStateEnum.WAIT_CHECK.getValue())
                    && clientType.equals(ClientTypeEnum.PC))) {
                throw new BrillilabException(ResultEnum.LAB_NO_PI_OR_LAB_AUDIT_WAIT_PC,
                        "您已经提交申请实验室信息，请您在邮箱中点击链接验证后再进行登录！");
            } else if ((labApply.getState().equals(LabAuditStateEnum.WAIT_CHECK.getValue())
                    && !clientType.equals(ClientTypeEnum.PC))) {
                throw new BrillilabException(ResultEnum.LAB_AUDIT_WAIT_APP, "您已经提交申请实验室信息，请您在邮箱中点击链接验证后再进行登录！");
            } else if (labApply.getState().equals(LabAuditStateEnum.AUDIT_NOT_PASS.getValue())) {
                if (StringUtils.isNotBlank(auditInfo)) {
                    auditInfo = String.format("您的实验室申请未通过，原因如下：%s", labApply.getAuditInfo());
                } else {
                    auditInfo = "您的实验室申请未通过";
                }
                throw new BrillilabException(ResultEnum.LAB_AUDIT_FAIL, auditInfo);
            }
        }
    }

    /**
     * 用户磁卡登录
     *
     * @param cardNo
     * @return
     */
    public UserInfoVo userLogin(Long labId, String cardNo, ClientTypeEnum clientType) {
        // 根据labId和cardNo获取用户信息
        UserInfoVo userInfo = getUserInfo(labId, cardNo);
        // 设置用户登录信息缓存
        this.setUserCache(userInfo, clientType);
        return userInfo;
    }

    /**
     * 设置用户登录信息缓存
     *
     * @param userInfo
     * @param clientType
     */
    public void setUserCache(UserInfoVo userInfo, ClientTypeEnum clientType) {
        if (userInfo != null) {
            // 设置用户登录信息缓存
            String token = CodeUtil.getToken(clientType);
            userInfo.setToken(token);
            if (clientType.equals(ClientTypeEnum.IOS) || clientType.equals(ClientTypeEnum.ANDROID)) {
                redisCache.set(KeyProfixConstant.TOKEN + token, userInfo, userLoginProperties.getInvalidTimeApp());
            } else {
                redisCache.set(KeyProfixConstant.TOKEN + token, userInfo, userLoginProperties.getInvalidTimePc());
                if (userLoginProperties.isSso()) {
                    this.ssoLogin(userInfo.getLabMemberId());
                }
            }
            this.setTokenList(token, userInfo.getLabMemberId());
        }
    }

    /**
     * 进行单点登入删除其他token
     *
     * @param labMemberId
     */
    private void ssoLogin(Long labMemberId) {
        Set<String> tokenList = getTokenList(labMemberId);
        if (!CollectionUtils.isEmpty(tokenList)) {
            for (Iterator<String> iterator = tokenList.iterator(); iterator.hasNext(); ) {
                String strToken = (String) iterator.next();
                if (strToken.startsWith(ClientTypeEnum.PC.getValue())
                        || strToken.startsWith(ClientTypeEnum.WEB.getValue())) {
                    redisCache.delete(KeyProfixConstant.TOKEN + strToken);
                }
            }
        }
    }

    /**
     * 获取token列表缓存
     *
     * @param labMemberId
     * @return
     */
    @SuppressWarnings({"unchecked"})
    public Set<String> getTokenList(Long labMemberId) {
        return (Set<String>) redisCache.getObj("tokenList:" + labMemberId);
    }

    /**
     * 设置token列表缓存
     *
     * @param token
     */
    private void setTokenList(String token, Long labMemberId) {
        if (labMemberId != null) {
            Set<String> tokenList = getTokenList(labMemberId);
            if (tokenList == null) {
                tokenList = new TreeSet<>();
            }
            tokenList.add(token);
            setTokenList(labMemberId, tokenList);
        }
    }

    /**
     * 设置token列表缓存
     *
     * @param labMemberId
     * @param tokenList
     */
    private void setTokenList(Long labMemberId, Set<String> tokenList) {
        if (tokenList.size() > 0) {
            redisCache.set("tokenList:" + labMemberId, tokenList, TimeConstant.ONE_HOUR);
        } else {
            redisCache.delete("tokenList:" + labMemberId);
        }
    }

    /**
     * 获取用户本人信息
     *
     * @return
     */

    public Users getUser(Long id) {
        return usersService.selectUser(id, UserEnum.State.NORMAL.getValue());
    }

    /**
     * 根据指定用户Id集合获取用户列表
     *
     * @param userIdList
     * @return
     */
    public List<Users> getUserList(List<Long> userIdList) {
        return usersService.selectUserList(userIdList, UserEnum.State.NORMAL.getValue());
    }

    /**
     * 手机号查询用户
     *
     * @param mobile
     * @return
     */
    public Users getUser(String mobile) {
        return usersService.selectUser(mobile, UserEnum.State.NORMAL.getValue());
    }

    /**
     * 根据邮箱地址获取用户
     *
     * @param mail
     * @return
     */
    public Users getUserByEmail(String mail) {
        return usersService.selectUserByEmail(mail, UserEnum.State.NORMAL.getValue());
    }

    /**
     * 根据手机号查询用户注册信息
     *
     * @param mobile
     * @return
     */
    public UserRegVo getUserRegVo(String mobile) {
        Users user = usersService.selectUser(mobile, UserEnum.State.NORMAL.getValue());
        UserRegVo userRegVo = null;
        if (user != null) {
            userRegVo = new UserRegVo();
            BeanUtils.copyProperties(user, userRegVo);
            userRegVo.setTips("此用户已注册，请填写信息后加入实验室");
            List<LabMember> labMembers = labMemberService.selectAllByUserId(user.getId());
            if (labMembers != null && labMembers.size() > 0) {
                labMembers.sort(Comparator.comparing(LabMember::getUpdateTime).reversed());
                LabMember labMember = labMembers.get(0);
                userRegVo.setDutyName(labMember.getDuty());
                Map<Integer, String> userDutyMap = dictService.getUserDutyMap();
                if (userDutyMap != null) {
                    for (Map.Entry<Integer, String> entry : userDutyMap.entrySet()) {
                        Integer mapKey = entry.getKey();
                        String mapValue = entry.getValue();
                        if (mapValue.equals(labMember.getDuty())) {
                            userRegVo.setDuty(mapKey);
                        }
                    }
                }
            }
        }
        return userRegVo;
    }

    /**
     * 根据labId ,userId查找用户信息
     *
     * @param labId
     * @param userId
     * @return
     */
    public UserInfoVo getUserInfo(Long labId, Long userId) {
        UserInfoVo infoVo = null;
        Lab lab = labService.selectById(labId);
        if (lab != null && LabEnum.State.NORMAL.getValue().equals(lab.getState())) {
            LabMember labMember = labMemberService.selectMember(lab.getId(), userId);
            if (labMember != null) {
                Users users = this.getUser(userId);
                Assert.isTrue(users != null, "用户不存在！");
                infoVo = MyBeanUtils.copyBean(users, UserInfoVo.class);
                List<LabMember> labMembers = labMemberService.selectListByUserId(userId);

                TeamMember teamMember = teamMemberService.selectByLabMemberId(labMember.getId());
                if (teamMember != null && teamMember.getIsLeader().equals(BoolEnum.TRUE.getValue())) {
                    infoVo.setIsTeamLeader(BoolEnum.TRUE.getValue());
                } else {
                    infoVo.setIsTeamLeader(BoolEnum.FALSE.getValue());
                }

                infoVo.setIsVip(lab.getIsVip());
                infoVo.setLabNum(labMembers != null ? labMembers.size() : 0);
                infoVo.setLabId(lab.getId());
                infoVo.setLabName(lab.getName());
                infoVo.setOwnerId(lab.getOwnerId());
                infoVo.setDuty(labMember.getDuty());

                infoVo.setLabMemberId(labMember.getId());
                infoVo.setPowers(labMemberPowerService.selectList(infoVo.getLabId(), labMember.getId()));
                infoVo.setUserPayType(users.getPayType());

                // setLabExpireInfo(infoVo, lab);
//                setUserExpireInfo(infoVo);
            } else {
                Users users = this.getUser(userId);
                Assert.isTrue(users != null, "用户不存在！");
                //用户多实验室且移除某一个实验室时只更新了数据库的labId但未未更新缓存中实验室Id，会导致token缓存的LabId还是旧实验室Id，查到不到lab，因此增加判断uses表中LabId是否为null，不会null则重新设置用户信息
                if(users.getLabId()!=null){
                    infoVo=   this.getUserInfo(users.getLabId(),users.getId());
                }else{
                    infoVo = MyBeanUtils.copyBean(users, UserInfoVo.class);
                }
            }
        }
        return infoVo;
    }

    private void setLabExpireInfo(UserInfoVo infoVo, Lab lab) {
        infoVo.setLabPayType(lab.getPayType());
        if (lab.getPayType().equals(LabPayTypeEnum.TRY.getValue())) {
            // labExpireInfo
            Long expireDays = TimeUtil.getBetweenDays(System.currentTimeMillis(), lab.getExpireDate().getTime());
            infoVo.setExpireDays(Math.abs(expireDays));
            infoVo.setHasExpired(System.currentTimeMillis()>lab.getExpireDate().getTime());//当前时间>过期时间，即为过期
            String info;
            // expiredText
            SystemConfig systemConfig = systemConfigService.selectByCode(SystemConfigConstant.RE_KF);
            String kfWxAccount = "";//客服微信号
            if (systemConfig != null) {
                JSONObject jsonObject = JSONObject.parseObject(systemConfig.getValue());
                kfWxAccount = jsonObject.get("wxAccount").toString();
                infoVo.setKfWxAccount(kfWxAccount);
            }
            if (expireDays > 0) {
                info = "<span>您的LabInOne小管家试用期</span>" + "<span style='color:#EB5444'>还剩%s天</span>"
                        + "<span>,如果您对我提供的服务还满意的话，请快快分享为小管家转正，让我继续为您服务吧~</span>"
                        + "<br/><span>使用APP分享至朋友圈，并截图，发送给客服人员即可转正</span>"
                        + "<br/><span>客服微信：</span><span style='color:#58A2FB'>%s</span>";
                infoVo.setExpiredText(String.format(info, expireDays.toString(), kfWxAccount));
            } else {
                if(expireDays==0 && System.currentTimeMillis()<infoVo.getExpireDate().getTime()){
                    //当天到期
                    info = "<span>您的LabInOne小管家试用期</span>" + "<span style='color:#EB5444'>今天到期</span>"
                            + "<span>,如果您对我提供的服务还满意的话，请快快分享为小管家转正，让我继续为您服务吧~</span>"
                            + "<br/><span>使用APP分享至朋友圈，并截图，发送给客服人员即可转正</span>"
                            + "<br/><span>客服微信：</span><span style='color:#58A2FB'>%s</span>";
                }else {
                    info = "<span>您的LabInOne小管家试用期</span>" + "<span style='color:#EB5444'>已过期</span>"
                            + "<span>,如果您对我提供的服务还满意的话，请快快分享为小管家转正，让我继续为您服务吧~</span>"
                            + "<br/><span>使用APP分享至朋友圈，并截图，发送给客服人员即可转正</span>"
                            + "<br/><span>客服微信：</span><span style='color:#58A2FB'>%s</span>";
                }
                infoVo.setExpiredText(String.format(info, kfWxAccount));
            }
            // expiredTextAlert
            // 试用版 1 3 7 <=0 会弹出
            if ((expireDays == 1 || expireDays == 3 || expireDays == 7 || expireDays <= 0)) {
                infoVo.setExpiredTextAlert(true);
            } else {
                infoVo.setExpiredTextAlert(false);
            }

            infoVo.setRemainCount(0);
            // 邀请码信息显示赋值
            if (infoVo.getIsOwner()) {
                HomeInviteCodeInfo inviteCodeInfo = getInviteCodeInfo(infoVo);
                if (inviteCodeInfo != null) {
                    infoVo.setShowInviteCode(inviteCodeInfo.getCodeList() != null);
                    infoVo.setRemainCount(inviteCodeInfo.getRemainCount());
                    infoVo.setInviteCodeList(inviteCodeInfo.getCodeList());
                    infoVo.setTips(inviteCodeInfo.getTips());
                }
            }
        }
    }

    /**
     * 设置用户过期信息
     *
     * @param infoVo
     */
    private void setUserExpireInfo(UserInfoVo infoVo) {
        if (infoVo != null && infoVo.getUserPayType().equals(UserPayTypeEnum.TRY.getValue())
                && infoVo.getExpireDate() != null) {
            // userExpireInfo
            Long expireDays = TimeUtil.getBetweenDays(System.currentTimeMillis(), infoVo.getExpireDate().getTime());
            infoVo.setExpireDays(Math.abs(expireDays));
            infoVo.setHasExpired(System.currentTimeMillis()>infoVo.getExpireDate().getTime());//当前时间>过期时间，即为过期
            String info;
            SystemConfig systemConfig = systemConfigService.selectByCode(SystemConfigConstant.RE_KF);
            String kfWxAccount = "";//客服微信号
            if (systemConfig != null) {
                JSONObject jsonObject = JSONObject.parseObject(systemConfig.getValue());
                kfWxAccount = jsonObject.get("wxAccount").toString();
                infoVo.setKfWxAccount(kfWxAccount);
            }
            // expiredText
            if (expireDays > 0) {
                info = "<span>您的LabInOne小管家试用期</span>" + "<span style='color:#EB5444'>还剩%s天</span>"
                        + "<span>,如果您对我提供的服务还满意的话，请快快分享为小管家转正，让我继续为您服务吧~</span>"
                        + "<br/><span>使用APP分享至朋友圈，并截图，发送给客服人员即可转正</span>"
                        + "<br/><span>客服微信：</span><span style='color:#58A2FB'>%s</span>";
                infoVo.setExpiredText(String.format(info, expireDays.toString(), kfWxAccount));
            } else {
                if(expireDays==0 && System.currentTimeMillis()<infoVo.getExpireDate().getTime()){
                    //当天到期
                    info = "<span>您的LabInOne小管家试用期</span>" + "<span style='color:#EB5444'>今天到期</span>"
                            + "<span>,如果您对我提供的服务还满意的话，请快快分享为小管家转正，让我继续为您服务吧~</span>"
                            + "<br/><span>使用APP分享至朋友圈，并截图，发送给客服人员即可转正</span>"
                            + "<br/><span>客服微信：</span><span style='color:#58A2FB'>%s</span>";
                }else {
                    info = "<span>您的LabInOne小管家试用期</span>" + "<span style='color:#EB5444'>已过期</span>"
                            + "<span>,如果您对我提供的服务还满意的话，请快快分享为小管家转正，让我继续为您服务吧~</span>"
                            + "<br/><span>使用APP分享至朋友圈，并截图，发送给客服人员即可转正</span>"
                            + "<br/><span>客服微信：</span><span style='color:#58A2FB'>%s</span>";
                }
                infoVo.setExpiredText(String.format(info, kfWxAccount));
            }
            // expiredTextAlert
            // 试用版 1 3 7 <=0 会弹出
            if ((expireDays == 1 || expireDays == 3 || expireDays == 7 || expireDays <= 0)) {
                infoVo.setExpiredTextAlert(true);
            } else {
                infoVo.setExpiredTextAlert(false);
            }
        }

        infoVo.setRemainCount(0);
        // 邀请码信息显示赋值
        if (infoVo.getIsOwner()) {
            HomeInviteCodeInfo inviteCodeInfo = getInviteCodeInfo(infoVo);
            if (inviteCodeInfo != null) {
                infoVo.setShowInviteCode(inviteCodeInfo.getCodeList() != null);
                infoVo.setRemainCount(inviteCodeInfo.getRemainCount());
                infoVo.setInviteCodeList(inviteCodeInfo.getCodeList());
                infoVo.setTips(inviteCodeInfo.getTips());
            }
        }
    }

    /**
     * 通过labId , cardNo查找用户信息
     *
     * @param labId
     * @param cardNo
     * @return
     */
    public UserInfoVo getUserInfo(Long labId, String cardNo) {
        Lab lab = labService.selectById(labId);
        Assert.isTrue(lab != null, "实验室不存在");
        // 查找用户卡信息
        LabUserCard labUserCard = cardService.selectCard(labId, cardNo);
        Assert.isTrue(labUserCard != null && labId.equals(labUserCard.getLabId()), "该磁卡非本实验室磁卡！");

        if (!LabUserCardEnum.State.TIED_CARD.getValue().equals(labUserCard.getState())) {
            throw new BrillilabException(ResultEnum.DATA_NOT_EXIST); // 磁卡未绑定用户返回1100
        }

        Assert.isTrue(labUserCard.getUserId() != null, "磁卡未绑定用户信息！");

        // 查找用户信息
        Users users = usersService.selectUser(labUserCard.getUserId(), UserEnum.State.NORMAL.getValue());
        Assert.notNull(users, "用户状态异常！");

        List<LabMember> labMembers = labMemberService.selectListByUserId(users.getId());

        // 获取用户权限列表
        LabMember labMember = labMemberService.selectMember(lab.getId(), users.getId());
        Assert.isTrue(labMember != null && labMember.getState().equals(LabMemberEnum.State.STATE_IN.getValue()),
                "用户不是实验室成员");

        List<LabMemberPower> powers = labMemberPowerService.selectList(users.getLabId(), labMember.getId());

        UserInfoVo userInfoVo = MyBeanUtils.copyBean(users, UserInfoVo.class);
        TeamMember teamMember = teamMemberService.selectByLabMemberId(labMember.getId());
        if (teamMember != null && teamMember.getIsLeader().equals(BoolEnum.TRUE.getValue())) {
            userInfoVo.setIsTeamLeader(BoolEnum.TRUE.getValue());
        } else {
            userInfoVo.setIsTeamLeader(BoolEnum.FALSE.getValue());
        }
        userInfoVo.setLabId(lab.getId());
        userInfoVo.setLabName(lab.getName());
        userInfoVo.setLabMemberId(labMember.getId());
        userInfoVo.setOwnerId(lab.getOwnerId());
        userInfoVo.setPowers(powers);
        userInfoVo.setLabNum(labMembers != null ? labMembers.size() : 0);
        userInfoVo.setDuty(labMember.getDuty());
        userInfoVo.setIsVip(lab.getIsVip());
        return userInfoVo;
    }

    /**
     * Token获取用户信息
     *
     * @return UserInfoVo (labId labMemberId)
     */
    public UserInfoVo getUserByToken(String token) {
        // 通过Token获取用户信息
        UserInfoVo userInfoVo = (UserInfoVo) redisCache.getObj(KeyProfixConstant.TOKEN + token);
        if (userInfoVo != null) {
            // 重置缓存时效
            String client = token.split("_")[0];
            if (client.equals(ClientTypeEnum.ANDROID.getValue()) || client.equals(ClientTypeEnum.IOS.getValue())) {
                redisCache.set(KeyProfixConstant.TOKEN + token, userInfoVo, TimeConstant.ONE_MONTH);
            } else {
                redisCache.set(KeyProfixConstant.TOKEN + token, userInfoVo, TimeConstant.HARF_HOUR);
            }
        }
        if (userInfoVo == null) {
            throw new BrillilabException(ResultEnum.USER_NOT_LOGIN, "由于您长时间未操作，请重新登陆！");
        }

        Lab lab = labService.selectById(userInfoVo.getLabId());
        if (lab != null) {
            // setLabExpireInfo(userInfoVo, lab);
            // 赋值初始化，解决前期登录部分属性未赋值的问题
            Users userInfo = getUser(userInfoVo.getId());
            userInfoVo.setUserPayType(userInfo.getPayType());
            userInfoVo.setExpireDate(userInfo.getExpireDate());
//            setUserExpireInfo(userInfoVo);
        } else {
            userInfoVo.setExpireDays(0);
            userInfoVo.setHasExpired(false);
        }

        // 更细lastLoginTime
        Users users = getUser(userInfoVo.getId());
        if (users == null) {
            throw new BrillilabException(ResultEnum.USER_NOT_EXIST, ResultEnum.USER_NOT_EXIST.getMessage());
        }
        users.setId(userInfoVo.getId());
        users.setLastLoginTime(new Date());
        usersService.updateById(users);

        return userInfoVo;
    }

    /**
     * 获取默认实验室用户信息
     *
     * @return
     */
    public UserInfoVo getUserById(Long userId) {
        Users user = this.getUser(userId);
        Assert.isTrue(user != null, "用户不存在！");
        UserInfoVo infoVo = MyBeanUtils.copyBean(user, UserInfoVo.class);

        Lab lab = labService.selectById(infoVo.getLabId());
        if (lab == null) {
            List<LabMember> labMemberList = labMemberService.selectListByUserId(user.getId());
            if (!CollectionUtils.isEmpty(labMemberList)) {
                Long labId = labMemberList.get(0).getLabId();
                lab = labService.selectById(labId);
                user.setLabId(labId);
                usersService.updateById(user);
            }
        }
        if (lab != null && LabEnum.State.NORMAL.getValue().equals(lab.getState())) {
            LabMember labMember = labMemberService.selectMember(infoVo.getLabId(), infoVo.getId());
            if (labMember != null) {
                infoVo.setLabId(lab.getId());
                infoVo.setLabName(lab.getName());
                infoVo.setOwnerId(lab.getOwnerId());
                List<LabMember> labMembers = labMemberService.selectListByUserId(userId);

                TeamMember teamMember = teamMemberService.selectByLabMemberId(labMember.getId());
                if (teamMember != null && teamMember.getIsLeader().equals(BoolEnum.TRUE.getValue())) {
                    infoVo.setIsTeamLeader(BoolEnum.TRUE.getValue());
                } else {
                    infoVo.setIsTeamLeader(BoolEnum.FALSE.getValue());
                }

                infoVo.setIsVip(lab.getIsVip());
                infoVo.setLabNum(labMembers != null ? labMembers.size() : 0);
                infoVo.setLabMemberId(labMember.getId());
                infoVo.setDuty(labMember.getDuty());
                infoVo.setPowers(labMemberPowerService.selectList(infoVo.getLabId(), labMember.getId()));
            }
        } else {
            infoVo.setIsVip(0);
            infoVo.setLabNum(0);
        }
        return infoVo;
    }

    /**
     * 切换实验室
     *
     * @param token
     * @param labId
     * @return
     */
    public UserInfoVo changeLab(String token, Long labId) {

        // 查询用户信息缓存
        UserInfoVo userInfo = (UserInfoVo) redisCache.getObj(KeyProfixConstant.TOKEN + token);
        Assert.isTrue(userInfo != null, "用户登录信息失效！");

        // 从原有tokenList中移除
        this.removeFromTokenList(userInfo);

        // 查询用用户信息
        Users user = getUser(userInfo.getId());

        // 查询实验室信息
        Lab lab = labService.selectById(labId);
        Assert.isTrue(lab != null && !lab.getState().equals(LabEnum.State.DELETE.getValue()), "实验室不存在或已删除！");

        List<LabMember> labMemberList = labMemberService.selectListByUserId(user.getId());

        // 判断用户是否存在该实验室成员
        LabMember labMember = labMemberService.selectMember(labId, userInfo.getId());
        Assert.isTrue(labMember != null && !labMember.getState().equals(LabMemberEnum.State.STATE_OUT.getValue()),
                "用户不是实验室成员");

        // 查询labMemberPowers
        List<LabMemberPower> labMemberPowers = labMemberPowerService.selectList(labId, labMember.getId());

        List<LabMember> labMembers = labMemberService.selectListByUserId(user.getId());

        // 更改默认实验室(lab_id)
        user.setLabId(labId);
        usersService.updateById(user);

        // 更改用户信息缓存的默认实验室(lab_id)
        TeamMember teamMember = teamMemberService.selectByLabMemberId(labMember.getId());
        if (teamMember != null && teamMember.getIsLeader().equals(BoolEnum.TRUE.getValue())) {
            userInfo.setIsTeamLeader(BoolEnum.TRUE.getValue());
        } else {
            userInfo.setIsTeamLeader(BoolEnum.FALSE.getValue());
        }
        userInfo.setLabId(labId);
        userInfo.setLabName(lab.getName());
        userInfo.setLabMemberId(labMember.getId());
        userInfo.setPowers(labMemberPowers);
        userInfo.setOwnerId(lab.getOwnerId());
        userInfo.setLabNum(labMemberList.size());
        userInfo.setDuty(labMember.getDuty());
        userInfo.setIsVip(lab.getIsVip());
        userInfo.setLabNum(labMembers != null ? labMembers.size() : 0);

        // 更新用户缓存
        this.resetUserCache(token, userInfo);
        this.setTokenList(token, userInfo.getLabMemberId());

        return userInfo;
    }

    /**
     * 从原有tokenList中移除
     *
     * @param userInfo
     */
    private void removeFromTokenList(UserInfoVo userInfo) {
        Set<String> tokenList = this.getTokenList(userInfo.getLabMemberId());
        if (tokenList != null) {
            tokenList.remove(userInfo.getToken());
            this.setTokenList(userInfo.getLabMemberId(), tokenList);
        }
    }

    /**
     * 用户登出
     *
     * @param token
     * @return
     */
    public void userLogout(String token) {
        UserInfoVo userInfo = this.getUserByToken(token);
        // 删除用户信息缓存
        redisCache.delete(KeyProfixConstant.TOKEN + token);
        // 清理TokenList
        this.removeFromTokenList(userInfo);
    }

    /**
     * 校验证件号或邮箱
     *
     * @param uavReq
     * @param userInfo
     */
    public void validateCertificateNoOrEmail(UserAuthValidateReq uavReq, UserInfoVo userInfo) {
        String certificateNo = StringUtils.trimToNull(uavReq.getCertificateNo());
        if (ValidatorUtil.isCertificateNo(certificateNo)) {
            Assert.isTrue(certificateNo.equals(userInfo.getCertificateNo()), "证件号或邮箱错误！");
        } else if (ValidatorUtil.isEmail(certificateNo)) {
            Assert.isTrue(certificateNo.equals(userInfo.getEmail()), "证件号或邮箱错误！");
        } else {
            throw new BrillilabException("证件号或邮箱错误！");
        }
    }

    /**
     * 修改用户安全信息身份验证
     *
     * @param uavReq
     * @param userInfo
     * @return
     */
    public IdentityValidateResp doIdentityValidate(UserAuthValidateReq uavReq, UserInfoVo userInfo) {
        // 获取验证类型，根据验证类型进行不同验证
        boolean rs = false;
        if (uavReq.getType().equals(UserAuthValidateReq.Type.MOBILE.getCode())) {
            // 手机验证码校验
            rs = this.validateIdentityByMobile(userInfo.getMobile(), uavReq.getValidateCode());
            Assert.isTrue(rs, "验证码错误！");
        } else if (uavReq.getType().equals(UserAuthValidateReq.Type.EMAIL.getCode())) {
            // 邮箱验证码验证
            rs = this.validateIdentityByEmail(userInfo.getEmail(), uavReq.getValidateCode());
            Assert.isTrue(rs, "验证码错误！");
        } else if (uavReq.getType().equals(UserAuthValidateReq.Type.PASSWORD.getCode())) {
            // 账号密码验证
            rs = this.validateIdentityByPassword(userInfo.getMobile(), uavReq.getPassword());
            Assert.isTrue(rs, "登录密码错误！");
        } else if (uavReq.getType().equals(UserAuthValidateReq.Type.SECURITY_PWD.getCode())) {
            // 根据数据密码验证
            rs = this.validateIdentityBySecurityPwd(userInfo.getMobile(), uavReq.getSecurityPwd());
            Assert.isTrue(rs, "数据密码错误！");
        } else {
            throw new BrillilabException(ResultEnum.FAILURE, "验证类型不存在！");
        }

        // 生成校验成功缓存信息
        String validateId = CodeUtil.getUUID();
        redisCache.set(KeyProfixConstant.VALIDATE_ID + userInfo.getId(), validateId);

        // 邮箱提示
        LabApply labApply = labApplyService.selectAuditPassOne(userInfo.getMobile());
        UserInviteAudit userInviteAudit = userInviteAuditService.selectFirstAuditPassOne(userInfo.getLabId(),
                userInfo.getMobile());

        String email = null;
        if (labApply != null || userInviteAudit != null) {
            if (labApply != null) {
                email = labApply.getOrgEmail();
            } else {
                email = userInviteAudit.getOrgEmail();
            }
        }

        IdentityValidateResp ivr = new IdentityValidateResp();
        ivr.setUserId(userInfo.getId());
        ivr.setValidateId(validateId);
        if (StringUtils.isNotBlank(email)) {
            if (isEmailWithOutAudit(email)) {
                ivr.setIsNoAuditIn(BoolEnum.TRUE.getValue());
                ivr.setPlaceHolder("请输入新的学术机构邮箱");
            } else {
                ivr.setIsNoAuditIn(BoolEnum.FALSE.getValue());
                ivr.setPlaceHolder("请输入新的邮箱");
            }
        } else {
            ivr.setIsNoAuditIn(BoolEnum.FALSE.getValue());
            ivr.setPlaceHolder("请输入新的邮箱");
        }

        return ivr;
    }

    private boolean isEmailWithOutAudit(String email) {
        return systemConfigService.checkEmailFormat(email);
    }

    /**
     * 手机验证码身份校验
     *
     * @param mobile
     * @param validateCode
     * @return
     */
    public boolean validateIdentityByMobile(String mobile, String validateCode) {
        Assert.isTrue(StringUtils.isNotBlank(validateCode), "请输验证码！");
        return messageLogic.checkVerifyCode(mobile, validateCode);
    }

    /**
     * 邮箱验证码身份校验
     *
     * @param email
     * @param validateCode
     * @return
     */
    public boolean validateIdentityByEmail(String email, String validateCode) {
        Assert.isTrue(StringUtils.isNotBlank(validateCode), "请输验证码！");
        return messageLogic.checkEmailVerifyCode(email, validateCode);
    }

    /**
     * 通过用户密码验证
     *
     * @param mobile
     * @param password
     * @return
     */
    public boolean validateIdentityByPassword(String mobile, String password) {
        return usersService.selectUser(mobile, password, UserEnum.State.NORMAL.getValue()) != null;
    }

    /**
     * 通过用户数据密码验证
     *
     * @param mobile
     * @param securityPwd
     * @return
     */
    public boolean validateIdentityBySecurityPwd(String mobile, String securityPwd) {
        return usersService.selectUser(mobile, securityPwd) != null;
    }

    /**
     * 确认身份校验
     *
     * @param validateCode
     * @return
     */
    public boolean checkIdentityValidation(Long userId, String validateCode) {
        String rs = (String) redisCache.getObj(KeyProfixConstant.VALIDATE_ID + userId);
        // 确认成功删除缓存
        if (!StringUtils.isBlank(rs) && rs.equals(validateCode)) {
            redisCache.delete(KeyProfixConstant.VALIDATE_ID + userId);
            return true;
        }
        return false;
    }

    /**
     * 修改手机号
     *
     * @param userInfo
     * @param mobile
     * @param validateCode
     * @return
     */
    public UserInfoVo modifyMobile(UserInfoVo userInfo, String mobile, String validateCode, String validateId) {

        Assert.isTrue(StringUtils.isNotBlank(mobile), "请输入手机号！");
        Assert.isTrue(ValidatorUtil.isPhone(mobile), "请输入正确的手机号！");

        Users exist = usersService.selectUser(mobile, UserEnum.State.NORMAL.getValue());
        Assert.isNull(exist, "手机号码已被注册！");

        // 短信验证码校验
        Assert.isTrue(messageLogic.checkVerifyCode(mobile, validateCode), "短信校验失败，验证码错误或已失效！");

        // 确认身份校验
        Assert.isTrue(checkIdentityValidation(userInfo.getId(), validateId), "确认身份校验结果失败!");

        // 修改用户手机号
        Users users = usersService.selectUser(userInfo.getId(), UserEnum.State.NORMAL.getValue());
        Assert.isTrue(users != null, "用户已冻结或不存在");

        users.setMobile(mobile);
        userInfo.setMobile(mobile);
        usersService.updateById(users);

        return userInfo;
    }

    /**
     * 修改邮箱
     *
     * @param userInfo
     * @param email
     * @param validateCode
     * @return
     */
    public UserInfoVo modifyEmail(UserInfoVo userInfo, String email, String validateCode, String validateId) {

        Assert.isTrue(StringUtils.isNotBlank(email), "请填写邮箱！");
        Assert.isTrue(ValidatorUtil.isEmail(email), "邮箱格式错误！");

        List<Users> exists = usersService.selectUserList(email);
        Assert.isTrue(exists.size() == 0, "邮箱已被注册！");

        // 校验邮箱验证码
        boolean b = messageLogic.checkEmailVerifyCode(email, validateCode);
        Assert.isTrue(b, "验证码错误或已失效！");

        // 确认身份校验
        boolean b2 = checkIdentityValidation(userInfo.getId(), validateId);
        Assert.isTrue(b2, "确认身份校验结果失败!");

        // 修改邮箱
        Users users = usersService.selectUser(userInfo.getId(), UserEnum.State.NORMAL.getValue());
        Assert.isTrue(users != null, "用户已冻结或不存在");

        users.setEmail(email);
        userInfo.setEmail(email);
        usersService.updateById(users);

        return userInfo;
    }

    /**
     * 修改密码有校验
     *
     * @param userId
     * @param password
     * @return
     */
    public boolean modifyPasswordWithValidate(Long userId, String password, String validateId) {

        Assert.isTrue(StringUtils.isNotBlank(password), "请输入新密码！");

        Users users = usersService.selectUser(userId, UserEnum.State.NORMAL.getValue());
        Assert.notNull(users, "用户已冻结或不存在");

        // 确认身份校验
        Assert.isTrue(checkIdentityValidation(userId, validateId), "确认身份校验结果失败!");

        users.setPassword(DigestUtils.md5Hex(password.trim()).toUpperCase());

        return usersService.updateById(users);

    }

    /**
     * 修改密码
     *
     * @param userId
     * @param password
     * @return
     */
    public boolean modifyPassword(Long userId, String password) {

        Assert.isTrue(StringUtils.isNotBlank(password), "请输入新密码！");

        Users users = usersService.selectUser(userId, UserEnum.State.NORMAL.getValue());
        Assert.notNull(users, "用户已冻结或不存在");

        users.setPassword(DigestUtils.md5Hex(password.trim()).toUpperCase());

        return usersService.updateById(users);

    }

    /**
     * 修改数据密码
     *
     * @param userId
     * @param securityPwd
     * @return
     */
    public boolean modifySecurityPwd(Long userId, String securityPwd, String validateId) {

        Assert.isTrue(StringUtils.isNotBlank(securityPwd), "请输入新密码！");

        Users users = usersService.selectUser(userId, UserEnum.State.NORMAL.getValue());
        Assert.notNull(users, "用户已冻结或不存在");

        // 确认身份校验
        Assert.isTrue(checkIdentityValidation(userId, validateId), "确认身份校验结果失败!");

        users.setSecurityPwd(DigestUtils.md5Hex(securityPwd.trim()).toUpperCase());

        return usersService.updateById(users);
    }

    /**
     * 用户实验室列表
     *
     * @param id
     * @return
     */
    public List<LabInfoVo> getLabList(Long id) {
        return usersService.selectLabInfoVo(id, UserEnum.State.NORMAL.getValue());
    }

    /**
     * 忘记密码修改
     *
     * @param validateId
     * @param password
     * @return
     */
    public boolean forgetPasswordModify(String validateId, String password) {

        // 确认成功删除缓存
        Long userId = (Long) redisCache.getObj(KeyProfixConstant.VALIDATE_ID + validateId);
        Assert.isTrue(userId != null, "身份认证信息有误！");
        redisCache.delete(KeyProfixConstant.VALIDATE_ID + validateId);

        // 查询
        Users users = usersService.selectUser(userId, UserEnum.State.NORMAL.getValue());

        // 更新
        users.setPassword(DigestUtils.md5Hex(password).toUpperCase());

        return usersService.updateById(users);
    }

    /**
     * 修改密码信息
     *
     * @param userInfo
     * @param formInfo
     * @return
     */
    public boolean modifyPwdInfo(UserInfoVo userInfo, UserModifyPwdVo formInfo) {
        // 短信验证码校验
        messageLogic.checkVerifyCode(userInfo.getMobile(), formInfo.getVerifyCode());

        // 查询
        Users users = usersService.selectUser(userInfo.getId(), UserEnum.State.NORMAL.getValue());
        // 更新
        users.setPassword(DigestUtils.md5Hex(formInfo.getPassword()).toUpperCase());
        users.setSecurityPwd(DigestUtils.md5Hex(formInfo.getSecurityPwd()).toUpperCase());
        users.setIsChangedPwd(1);
        users.setFirstLoginTime(new Date());

        // 设置过期时间为30天
        Date expireDate = DateUtil.addDate(new Date(), 30);
        String dateString = DateUtil.dateString(expireDate, "yyyy-MM-dd 23:59:59");
        users.setExpireDate(DateUtil.stringToDate(dateString, "yyyy-MM-dd HH:mm:ss"));

        // 重设缓存
        resetUserCache(userInfo.getToken(), userInfo);

        if (usersService.updateById(users)) {

            // PI修改登录和数据密码成功
            Map<String, Object> paramMap = new LinkedHashMap<>();
            paramMap.put("PIName", users.getName());
            // 执行短信发送
            messageLogic.sendSmsContent(users.getMobile(), aliYunSms.getModifyLoginAndDataPasswordSuccessTemplate(),
                    paramMap);
            return true;
        }
        return false;
    }

    /**
     * 重设用户缓存信息时间
     *
     * @param token
     * @param userInfo
     */
    public void resetUserCache(String token, UserInfoVo userInfo) {
        if (StringUtils.isNotBlank(token)) {
            String client = token.split("_")[0];
            if (client.equals(ClientTypeEnum.ANDROID.getValue()) || client.equals(ClientTypeEnum.IOS.getValue())) {
                redisCache.set(KeyProfixConstant.TOKEN + token, userInfo,
                        redisCache.getExpireTime(KeyProfixConstant.TOKEN + token).intValue());
            } else {
                redisCache.set(KeyProfixConstant.TOKEN + token, userInfo, TimeConstant.HARF_HOUR);
            }
            this.deleteRefreshUser(token);
        }
    }

    /**
     * 用户已注册，用户已在实验室结果返回
     *
     * @param labId
     * @param mobile
     * @return
     */
    public ResponseVo getExistUserOrExistMemberResult(Long labId, String mobile) {
        Users user = this.getUser(mobile);
        if (user != null) {

            if (labId != null && labId > 0) {
                // 判断用户是否已加入实验室
                Lab lab = labService.selectById(labId);
                Assert.isTrue(lab != null && !lab.getState().equals(LabEnum.State.DELETE.getValue()), "实验室不存在或已删除！");
            }

            LabMember labMember = labMemberService.selectMember(labId, user.getId());
            if (labMember != null && labMember.getState().equals(LabMemberEnum.State.STATE_IN.getValue())) {
                ResponseVo failure = ResponseVo.failure(ResultEnum.USER_EXIST_CURRENT_LAB.getMessage());
                failure.setCode(ResultEnum.USER_EXIST_CURRENT_LAB.getCode());
                return failure;
            }

            String certificateNo = user.getCertificateNo();
            user.setCertificateNo(StringUtils.isNotBlank(certificateNo) && certificateNo.length() > 3
                    ? certificateNo.substring(0, 3) + "*****" + certificateNo.substring(certificateNo.length() - 3)
                    : null);
            ResponseVo failure;
            if (labId != null && labId > 0) {
                // 此手机号已注册，且在其它实验室，返回空，执行发送验证码
//                failure = ResponseVo.failure(ResultEnum.USER_EXIST_OTHER_LAB.getMessage());
//                failure.setCode(ResultEnum.USER_EXIST_OTHER_LAB.getCode());
                return null;
            } else {
                failure = ResponseVo.failure("该用户已注册!");
                failure.setCode(ResultEnum.USER_EXIST_OTHER_LAB.getCode());
            }
            failure.setData(user);
            return failure;
        }
        return null;
    }

    /**
     * 添加新成员信息验证（此方法做了短信验证码的校验）
     *
     * @param userInviteApplyInfoVo
     * @param user
     * @param token
     * @return
     */
    public ResponseVo validateMemberInfo(UserInviteApplyInfoVo userInviteApplyInfoVo, Users user, String token) {
        messageLogic.checkVerifyCode(userInviteApplyInfoVo.getMobile(), userInviteApplyInfoVo.getSmsCode());
        if (user != null) {
            // 操作人信息
            UserInfoVo userInfo = getUserByToken(token);
            if (user.getLabId() != null && user.getLabId() > 0) {
                ResponseVo failure;
                if (user.getLabId().equals(userInfo.getLabId())) {
                    // 提示已加入当前实验室
                    failure = ResponseVo.failure(ResultEnum.USER_EXIST_CURRENT_LAB.getMessage());
                    failure.setCode(ResultEnum.USER_EXIST_CURRENT_LAB.getCode());
                    return failure;
                }
            }
            // 已注册用户登录密码和数据密码赋值为空字符
            userInviteApplyInfoVo.setPassword("");
            userInviteApplyInfoVo.setSecurityPwd("");
        }

        // 机构邮箱验证码检测
        if (StringUtils.isNotEmpty(userInviteApplyInfoVo.getOrgEmail())) {
            String orgEmail = userInviteApplyInfoVo.getOrgEmail();
            Assert.isTrue(ValidatorUtil.isEmail(orgEmail), "请输入正确格式的邮箱！");
            boolean isRightEmail = labApplyLogic.checkEmailFormat(orgEmail);
            Assert.isTrue(isRightEmail, "非学术机构邮箱，禁止提交申请！");
//            Assert.isTrue(StringUtils.isNotEmpty(userInviteApplyInfoVo.getEmailCode()), "邮箱验证码不能为空！");
//            boolean emailCodeIsRight = messageLogic.checkEmailVerifyCode(userInviteApplyInfoVo.getOrgEmail(), userInviteApplyInfoVo.getEmailCode().trim());
//            Assert.isTrue(emailCodeIsRight, "邮箱验证码有误或已失效");
        }

        UserInfoVo userInfoVo = getUserByToken(token);
        UserInviteAudit apply = userInviteAuditLogic.submitLabMemberApply(userInviteApplyInfoVo, userInfoVo);
        if (apply != null && apply.getId() > 0) {
            if (apply.getState().equals(UserInviteAuditStateEnum.AUDIT_PASS.getValue())) {
                return ResponseVo.success("SUCCESS", "加入实验室成功");
            } else if (apply.getState().equals(UserInviteAuditStateEnum.WAIT_CHECK.getValue())) {
                return ResponseVo.success("SUCCESS", "验证信息已经发送到您的邮箱，请您在邮箱中点击链接验证");
            } else if (apply.getState().equals(UserInviteAuditStateEnum.WAIT_AUDIT.getValue())) {
                return ResponseVo.failure(ResultEnum.LAB_NO_PI_OR_LAB_AUDIT_WAIT_PC,
                        "您的申请已经提交成功！我们会在1—3个工作日内审核完成，审核完成后会短信通知您，请您耐心等待。", "Success");
            } else {
                return ResponseVo.failure("状态异常:" + apply.getState());
            }
        } else {
            return ResponseVo.failure("提交申请失败");
        }
    }

    /**
     * 用户已注册
     *
     * @param labId
     * @param mobile
     * @return
     */
    public void getExistUser(Long labId, String mobile) {
        Users user = this.getUser(mobile);
        Assert.isNull(user, "该手机号码已被注册!");
    }

    public UserInfoVo setLabInfoNull(String token, UserInfoVo userInfoVo) {
        userInfoVo.setLabId(null);
        userInfoVo.setLabName(null);
        userInfoVo.setLabMemberId(null);
        userInfoVo.setPowers(null);
        userInfoVo.setToken(token);
        return userInfoVo;
    }

    /**
     * 设置前端刷提示消息
     *
     * @param labMemberId 实验室成员ID
     * @param message     前端刷新提示消息
     */
    public void setRefreshUser(Long labMemberId, String message, boolean toCenter) {
        Set<String> tokenList = getTokenList(labMemberId);
        if (tokenList != null) {
            tokenList.forEach(token -> {
                ResponseVo responseVo;
                if (toCenter) {
                    responseVo = ResponseVo.failure(ResultEnum.REFRESH_USER_DIRECT_TO_CENTER, message, null);
                } else {
                    responseVo = ResponseVo.failure(ResultEnum.REFRESH_USER, message, null);
                }
                redisCache.set("message:" + token, responseVo, TimeConstant.HARF_HOUR);
            });
        }
    }

    /**
     * 获取前端刷新提示消息
     */
    public ResponseVo getRefreshUser(UserInfoVo infoVo, String token) {
        if (infoVo == null) {
            deleteRefreshUser(token);
            return null;
        }
        return (ResponseVo) redisCache.getObj("message:" + token);
    }

    /**
     * 删除前端刷新提示消息
     */
    public void deleteRefreshUser(String token) {
        redisCache.delete("message:" + token);
    }

    /**
     * [弹框]用户详情页——根据ID获取待审核用户信息
     *
     * @param userId
     * @return
     */
    public UserInfoVo getAuditInfo(Long userId, Long labId) {

        LabJoinAudit audit = labJoinAuditService.selectOne(userId, labId, LabJoinAuditStateEnum.PASS);
        Assert.notNull(audit, "该用户未申请加入实验室!");
        UserInfoVo userInfoVo = new UserInfoVo();
        userInfoVo.setLabId(audit.getLabId());
        userInfoVo.setId(audit.getUserId());
        userInfoVo.setName(audit.getName());
        userInfoVo.setDuty(audit.getDuty());
        userInfoVo.setImageUrl(audit.getImageUrl());
        userInfoVo.setSex(audit.getSex());
        userInfoVo.setSexName(audit.getSex() != null ? UserEnum.Sex.getKey(audit.getSex()) : "未知");
        return userInfoVo;
    }

    /**
     * 修改权限和小组
     *
     * @param modify
     * @param userInfo
     */
    public void entryPowerAndTeamModify(PowerAndDutyModifyVo modify, UserInfoVo userInfo) {

        Users users = usersService.selectUser(modify.getUserId(), UserEnum.State.NORMAL.getValue());
        Assert.notNull(users, "用户不存在!");

        LabJoinAudit audit = labJoinAuditService.selectOne(modify.getUserId(), userInfo.getLabId(),
                LabJoinAuditStateEnum.WAIT);

        if (modify.getPass() != null && modify.getPass().equals(BoolEnum.TRUE.getValue())) {
            Assert.notNull(audit, "已审阅,无法重复审阅!");
            Assert.isTrue(modify.getPowers() != null, "请求参数缺失！");

            LabMember exist = labMemberService.selectMember(userInfo.getLabId(), modify.getUserId());
            Assert.isNull(exist, "用户已加入实验室!");

            audit.setState(LabJoinAuditStateEnum.PASS.getValue());
            audit.setAuditTime(new Date());
            audit.setUpdateTime(new Date());
            labJoinAuditService.updateById(audit);

            LabMember labMember = new LabMember();
            labMember.setLabId(audit.getLabId());
            labMember.setUserId(audit.getUserId());
            labMember.setState(LabMemberEnum.State.STATE_IN.getValue());
            labMember.setDuty(audit.getDuty());
            labMember.setEntryDate(new Date());
            labMemberService.insert(labMember);

            modify.setLabMemberId(labMember.getId());
            labMemberLogic.modifyPowerAndTeam(modify, userInfo);

            // 待PI审核的用户
            List<UserInviteAudit> userInviteAudits = userInviteAuditService.selectList(userInfo.getLabId(),
                    audit.getMobile());
            UserInviteAudit userInviteAudit = userInviteAudits.stream()
                    .filter(e -> UserInviteAuditStateEnum.WAIT_PI_AUDIT.getValue().equals(e.getState()))
                    .max(Comparator.comparing(UserInviteAudit::getCreateTime)).orElse(null);
            if (userInviteAudit != null) {
                // 申请加入实验室状态更新为已通过
                userInviteAudit.setInviteState(UserAuditInviteStateEnum.INVITE_SUCCESS.getValue());
                userInviteAudit.setState(UserInviteAuditStateEnum.AUDIT_PASS.getValue());
                userInviteAudit.setEntryTime(new Date());
                userInviteAudit.setAuditTime(new Date());
                userInviteAudit.setUpdateTime(new Date());
                userInviteAuditService.updateById(userInviteAudit);
            }

            // 审核通过，发送“成员加入实验室成功”
            Map<String, Object> paramMap = new LinkedHashMap<>();
            paramMap.put("realName", audit.getName());
            paramMap.put("labName", userInfo.getLabName());
            // 执行短信发送
            messageLogic.sendSmsContent(audit.getMobile(), aliYunSms.getMemberJoinLabSuccessTemplate(), paramMap);
        } else if (modify.getPass() != null && modify.getPass().equals(BoolEnum.FALSE.getValue())) {
            Assert.notNull(audit, "已审阅,无法重复审阅!");
            audit.setState(LabJoinAuditStateEnum.NOT_PASS.getValue());
            labJoinAuditService.updateById(audit);

            // 待PI审核的用户
            List<UserInviteAudit> userInviteAudits = userInviteAuditService.selectList(userInfo.getLabId(),
                    audit.getMobile());
            UserInviteAudit userInviteAudit = userInviteAudits.stream()
                    .filter(e -> UserInviteAuditStateEnum.WAIT_PI_AUDIT.getValue().equals(e.getState()))
                    .max(Comparator.comparing(UserInviteAudit::getCreateTime)).orElse(null);
            if (userInviteAudit != null) {
                // 申请加入实验室状态更新为审核未通过
                userInviteAudit.setInviteState(UserAuditInviteStateEnum.INVITE_FAIL.getValue());
                userInviteAudit.setState(UserInviteAuditStateEnum.AUDIT_NOT_PASS.getValue());
                userInviteAudit.setEntryTime(new Date());
                userInviteAudit.setAuditTime(new Date());
                userInviteAudit.setUpdateTime(new Date());
                userInviteAuditService.updateById(userInviteAudit);
            }

            // 未通过
            Map<String, Object> paramMap = new LinkedHashMap<>();
            paramMap.put("realName", audit.getName());
            paramMap.put("labName", userInfo.getLabName());
            // 执行短信发送
            messageLogic.sendSmsContent(audit.getMobile(), aliYunSms.getApplyJoinLabAuditNotPassTemplate(), paramMap);
        } else if (modify.getPass() == null) {
            LabMember labMember = labMemberService.selectMember(userInfo.getLabId(), modify.getUserId());
            Assert.notNull(labMember, "成员不存在!");
            modify.setLabMemberId(labMember.getId());
            labMemberLogic.modifyPowerAndTeam(modify, userInfo);
        }

        // 更新实验室
        if (users.getLabId() == null) {
            users.setLabId(audit.getLabId());
            usersService.updateById(users);
        }
    }

    /**
     * 获取邀请码信息
     *
     * @param userInfoVo
     * @return
     */
    public HomeInviteCodeInfo getInviteCodeInfo(UserInfoVo userInfoVo) {
        Assert.isTrue(userInfoVo.getIsOwner(), "非PI用户禁止调用此接口！");
        HomeInviteCodeInfo homeInviteCodeInfo = new HomeInviteCodeInfo();
        homeInviteCodeInfo.setRemainCount(0);// 默认显示0
        List<InviteCode> inviteCodeList = inviteCodeService.getInviteCodeInfo(userInfoVo.getLabId());
        if (!CollectionUtils.isEmpty(inviteCodeList)) {
            // 获取可用推荐码数据
            List<InviteCode> remainList = inviteCodeList.stream().filter(p -> p.getState().equals(0))
                    .collect(Collectors.toList());
            homeInviteCodeInfo.setRemainCount(remainList != null ? remainList.size() : 0);

            inviteCodeList.sort(Comparator.comparing(InviteCode::getState));
            List<HomeInviteCodeItemVo> codeList = new ArrayList<>();
            HomeInviteCodeItemVo homeInviteCodeItemVo;
            for (InviteCode code : inviteCodeList) {
                homeInviteCodeItemVo = new HomeInviteCodeItemVo();
                homeInviteCodeItemVo.setInviteCode(code.getCode());
                homeInviteCodeItemVo.setIsUsed(code.getState());
                homeInviteCodeItemVo.setExpireDate(DateUtil.dateString(code.getExpireDate(), "yyyy-MM-dd"));
                codeList.add(homeInviteCodeItemVo);
            }
            homeInviteCodeInfo.setCodeList(codeList);
            homeInviteCodeInfo.setTips("每月1日赠送" + properties.getMonthCodeCount() + "张");
        }

        return homeInviteCodeInfo;
    }

    /**
     * 用户账号过期时间延长
     *
     * @param userInfoVo
     */
    public void delayUserExpireDate(UserInfoVo userInfoVo) {
        Users userInfo = getUser(userInfoVo.getId());
        if (userInfo != null) {
            // 100years
            // 设为免费版
            userInfo.setPayType(UserPayTypeEnum.FREE.getValue());
            userInfo.setExpireDate(DateUtil.addYear(new Date(), 100));
            usersService.updateById(userInfo);
        }
    }

}
